<template>
  <div class="container">
    <indicator
      :draggable="draggable"
      @rotate="rotate"
      @zoom="zoom"
      @reset="reset"
      @drawStart="drawStart"
      @drawEnd="moveStart"
      @addHighlightArea="addHighlightArea"
    />
    <div
      class="canvas-wrap"
      ref="canvasWrapRef"
      @mousedown="startDrawing"
      @mouseup="stopDrawing"
    >
      <v-stage :config="stageConfig" ref="stage">
        <v-layer>
          <!-- offsetX, offsetY 与css translate相反 -->
          <v-image
            :image="imageDom"
            :x="rectCenter.x"
            :y="rectCenter.y"
            :width="rectWidth"
            :height="rectHeight"
            :rotation="rectRotation"
            :scaleX="scale"
            :scaleY="scale"
            :offsetX="rectWidth / 2"
            :offsetY="rectHeight / 2"
            :draggable="draggable"
            @dragmove="handleRectDragMove"
          />
          <div v-for="(rect, index) in rectList" :key="index">
            <v-text
              :x="rectCenter.x"
              :y="rectCenter.y"
              :text="rect.title"
              :offsetX="getRectLeftTop(rect).offsetX"
              :offsetY="getRectLeftTop(rect).offsetY"
              :rotation="rect.rotation"
              :scaleX="rect.scale"
              :scaleY="rect.scale"
              :draggable="false"
            />
            <v-rect
              :x="rectCenter.x"
              :y="rectCenter.y"
              :width="rect.width"
              :height="rect.height"
              :rotation="rect.rotation"
              :scaleX="rect.scale"
              :scaleY="rect.scale"
              :offsetX="rect.offsetX"
              :offsetY="rect.offsetY"
              :draggable="rect.draggable"
              fill="rgba(0, 0, 0, 0)"
              stroke="red"
              :strokeWidth="1"
              @click="handleRectClick(index)"
            />
          </div>
        </v-layer>
      </v-stage>
    </div>
  </div>
</template>

<script>
import indicator from './components/indicator.vue'
export default {
  name: 'prev-img',
  components: {
    indicator,
  },
  data() {
    return {
      draggable: true,
      imageSrc:
        'https://oss.xinjiaoyu.com/exam/test/182769/10237/20230413_64aacbb1995a4d91b8a1ef8342518af5_36/20230413_64aacbb1995a4d91b8a1ef8342518af5_36_001_page.jpg',
      imageDom: new Image(),
      // 画布配置
      stageConfig: {
        width: 500,
        height: 300,
      },
      // 图片配置
      rectCenter: {
        x: 0,
        y: 0,
      },
      rectWidth: 0,
      rectHeight: 0,
      rectRotation: 0,
      scale: 1,
      initScale: 1,
      // 绘制矩形
      rectList: [],
      startX: 0,
      startY: 0,
      currentRectIndex: null,
      // 当前canvas绘制的内容
      canvasData: null,
    }
  },
  created() {
    this.initKeyBoardEvent()
    this.imageDom.src = this.imageSrc
    this.imageDom.crossOrigin = 'anonymous'
    this.imageDom.onload = () => {
      // 设置画布宽高
      const { width, height } = this.$refs.canvasWrapRef.getBoundingClientRect()
      this.stageConfig.width = width
      this.stageConfig.height = height
      // 设置图片中心点
      this.rectCenter.x = width / 2
      this.rectCenter.y = height / 2
      // 初始化图片大小
      const {
        width: rectWidth,
        height: rectHeight,
        scale,
      } = initImageSize(this.imageDom, this.stageConfig)
      this.rectWidth = rectWidth
      this.rectHeight = rectHeight
      this.initScale = scale
      this.initMouseEvent()
    }
  },
  methods: {
    // 旋转
    rotate(angle) {
      // if (this.rectList.length > 0) {
      //   ElMessage.warning('请删除矩形再旋转')
      //   return
      // }
      this.rectRotation += angle
      this.rectList.forEach((rect) => {
        rect.rotation += angle
      })
    },
    // 缩放
    zoom(scale) {
      const scaleRes = this.scale + scale
      if (scaleRes < 0.1) {
        return
      }
      this.scale = scaleRes
      this.rectList.forEach((rect) => {
        rect.scale += scale
      })
    },
    reset() {
      this.rectRotation = 0
      this.rectList = []
      const { width, height } = this.$refs.canvasWrapRef.getBoundingClientRect()
      this.rectCenter.x = width / 2
      this.rectCenter.y = height / 2
      this.scale = 1
    },

    // 绘制矩形 =========================================================== 开始
    drawStart() {
      this.draggable = false
    },
    startDrawing(event) {
      if (this.draggable) return
      console.log('startDrawing')
      const { x, y } = this.getMousePos(event)
      this.startX = x
      this.startY = y
      const { offsetX, offsetY } = canvasPosToImageCenter(
        { x, y },
        this.rectCenter,
      )
      this.rectList.push({
        title: Math.random().toString(36).substr(2),
        width: 0,
        height: 0,
        offsetX: offsetX / this.scale,
        offsetY: offsetY / this.scale,
        rotation: 0,
        scale: this.scale,
        draggable: false,
      })
      const canvas = this.getCanvas()
      canvas.addEventListener('mousemove', this.drawing)
    },
    drawing(event) {
      if (this.draggable) return
      console.log('drawing')
      const { x, y } = this.getMousePos(event)
      const width = x - this.startX
      const height = y - this.startY
      console.log(width, height);
      this.rectList[this.rectList.length - 1].width = width / this.scale
      this.rectList[this.rectList.length - 1].height = height / this.scale
    },
    stopDrawing() {
      if (this.draggable) return
      console.log('stopDrawing')
      const canvas = this.getCanvas()
      canvas.removeEventListener('mousemove', this.drawing)
      const rect = this.rectList[this.rectList.length - 1]
      if (Math.abs(rect.width) < 5 || Math.abs(rect.height) < 5) {
        this.rectList.pop()
        console.log('矩形过小被删除')
      } else {
        this.currentRectIndex = this.rectList.length - 1
      }
    },
    // 绘制结束
    drawEnd() {
      this.draggable = true
    },
    // 开启拖拽
    moveStart() {
      this.draggable = true
    },
    // 绘制矩形 =========================================================== 结束
    // 添加高亮区域
    addHighlightArea(rect) {
      console.log(rect)
    },
    handleRectClick(index) {
      this.currentRectIndex = index
    },
    // 注册键盘事件
    initKeyBoardEvent() {
      window.addEventListener('keydown', (event) => {
        const { key } = event
        console.log(key)
        switch (key) {
          case 'ArrowLeft':
            this.rectCenter.x -= 1
            break
          case 'ArrowRight':
            this.rectCenter.x += 1
            break
          case 'ArrowUp':
            this.rectCenter.y -= 1
            break
          case 'ArrowDown':
            this.rectCenter.y += 1
            break
          case 'Backspace':
            if (typeof this.currentRectIndex === 'number') {
              this.rectList.splice(this.currentRectIndex, 1)
              this.currentRectIndex = null
            }
            break
          default:
            break
        }
      })
    },
    // 注册滑轮事件
    initMouseEvent() {
      const canvas = this.getCanvas()
      canvas.addEventListener('wheel', (event) => {
        const { deltaY } = event
        if (deltaY > 0) {
          this.zoom(-0.1)
        } else {
          this.zoom(0.1)
        }
      })
    },
    // 复制当前canvas
    copyCanvasData() {
      const canvas = this.getCanvas()
      const ctx = canvas.getContext('2d')
      const { width, height } = canvas
      const imgData = ctx.getImageData(0, 0, width, height)
      return imgData
    },
    // 粘贴canvas
    pasteCanvasData(imgData) {
      const canvas = this.getCanvas()
      const ctx = canvas.getContext('2d')
      const { width, height } = canvas
      ctx.clearRect(0, 0, width, height)
      ctx.putImageData(imgData, 0, 0, 0, 0, width, height)
    },
    // 原图坐标转换为canvas坐标 未使用
    getCanvasPos(rect) {
      const { x, y, width, height, padding = 0 } = rect
      const { width: stageWidth, height: stageHeight } = this.stageConfig
      const shifting = {
        x: (stageWidth - this.rectWidth) / 2,
        y: (stageHeight - this.rectHeight) / 2,
      }
      return {
        x: x * this.initScale + shifting.x - padding * this.initScale,
        y: y * this.initScale + shifting.y - padding * this.initScale,
        width: (width + padding * 2) * this.initScale,
        height: (height + padding * 2) * this.initScale,
      }
    },
    getMousePos(event) {
      const rect = this.getCanvas().getBoundingClientRect()
      return {
        x: event.clientX - rect.left,
        y: event.clientY - rect.top,
      }
    },
    getCanvas() {
      return this.$refs.canvasWrapRef.querySelector('canvas')
    },
    handleRectDragMove(event) {
      const rect = event.target
      this.rectCenter.x = rect.x()
      this.rectCenter.y = rect.y()
    },
    getRectLeftTop,
  },
}

/**
 * 获取矩形左上角偏移量，width和height可以为负数
 * @param {Object} rect 矩形
 */
function getRectLeftTop(rect) {
  const { offsetX, offsetY, width, height } = rect
  return {
    offsetX: width > 0 ? offsetX : offsetX - width,
    offsetY: height > 0 ? offsetY : offsetY - height,
  }
}

/**
 * 将canvas坐标转换为图片中心坐标
 * @param {Object} canvas canvas坐标
 * @param {Object} center 图片中心坐标
 */
function canvasPosToImageCenter(canvas, center) {
  return {
    offsetX: center.x - canvas.x,
    offsetY: center.y - canvas.y,
  }
}
/**
 * 初始化图片大小
 * @param {Object} imageDom 图片宽高
 * @param {Object} stageConfig 画布宽高
 */
function initImageSize(imageDom, stageConfig) {
  const { width, height } = imageDom
  console.log('原图大小', width, height)
  const { width: stageWidth, height: stageHeight } = stageConfig
  const scaleX = stageWidth / width
  const scaleY = stageHeight / height
  const scale = Math.min(scaleX, scaleY)
  return {
    width: width * scale,
    height: height * scale,
    scale,
  }
}
</script>

<style scoped lang="scss">
.container {
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  .canvas-wrap {
    flex: 1;
    border: 1px solid#ccc;
  }
}
</style>
